package org.ocean.general.sample.helper;

import org.apache.ibatis.mapping.ResultMap;
import org.apache.ibatis.mapping.ResultMapping;
import org.apache.ibatis.session.Configuration;
import org.ocean.general.sample.annotation.IgnoreField;
import org.ocean.general.sample.annotation.PrimaryKey;
import org.ocean.general.sample.annotation.TableField;
import org.ocean.general.sample.annotation.TableInfo;
import org.ocean.general.sample.conditional.Conditional;
import org.ocean.general.sample.conditional.Sqls;
import org.ocean.general.sample.exception.BatisException;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicReference;

public class OptionalProviderHelper<T> {

    /**
     * 构建表名
     * @param bean
     * @return
     */
    public static String buildTableName(Class bean){
        TableInfo tableInfo = (TableInfo) bean.getAnnotation(TableInfo.class);
        if(Objects.nonNull(tableInfo) && StringUtils.hasLength(tableInfo.value())){
            return tableInfo.value();
        }else {
            throw new BatisException("实体类未配置TableInfo注解中需要操作的表名...");
        }
    }

    /**
     *
     * @param bean
     * @return
     */
    public static List<Field> getClassField(Class bean){
        List<Field> resultFieldList = new ArrayList<>();
        Field[] fields = bean.getDeclaredFields();
        List<Field> fieldList = new ArrayList<>(Arrays.asList(fields));
        Class<?> superClass = bean.getSuperclass();
        if(Objects.nonNull(superClass)) {
            Field[] supperFields = superClass.getDeclaredFields();
            fieldList.addAll(Arrays.asList(supperFields));
        }
        fieldList.stream().forEach(field -> {
            if(Modifier.isStatic(field.getModifiers()) || Modifier.isFinal(field.getModifiers())){
                return;
            }
            boolean isTransient = field.isAnnotationPresent(IgnoreField.class);
            if(isTransient){
                return;
            }
            resultFieldList.add(field);
        });
        return resultFieldList;
    }

    /**
     * 获取实体类对应的表列名
     * @param bean
     * @return
     */
    public static List<String> getFieldColumn(Class<?> bean){
        List<Field> allFieldList = getClassField(bean);
        List<String> columnList = new ArrayList<>(allFieldList.size());
        allFieldList.stream().forEach(field -> {
            TableField tableField = field.getAnnotation(TableField.class);
            if(Objects.nonNull(tableField) && Objects.nonNull(tableField.value())){
                columnList.add(tableField.value());
            }else {
                columnList.add(BatisHelper.getTableField(field.getName()));
            }
        });
        return columnList;
    }

    /**
     * 获取实体类的所有字段
     * @param bean
     * @return
     */
    public static List<String> getFieldParamterColumn(Class<?> bean){
        List<Field> allFieldList = getClassField(bean);
        List<String> columnList = new ArrayList<>(allFieldList.size());
        allFieldList.stream().forEach(field -> {
            columnList.add(field.getName());
        });
        return columnList;
    }

    /**
     * 查找主键
     * @param fieldList
     * @return
     */
    public static String findPrimaryKey(List<Field> fieldList){
        AtomicReference<String> primaryKeyAtomic = new AtomicReference<>();
        fieldList.stream().forEach(field -> {
            field.setAccessible(true);
            PrimaryKey primaryKey = field.getAnnotation(PrimaryKey.class);
            if(Objects.nonNull(primaryKey)){
                primaryKeyAtomic.set(field.getName());
                return;
            }
        });
        if(Objects.isNull(primaryKeyAtomic.get())){
            throw new BatisException("实体类未配置PrimaryKey注解...");
        }
        return primaryKeyAtomic.get();
    }

    /**
     * 查找主键
     * @param cla
     * @return
     */
    public static String findPrimaryKey(Class<?> cla){
        List<Field> fieldList = getClassField(cla);
        AtomicReference<String> primaryKeyAtomic = new AtomicReference<>();
        fieldList.stream().forEach(field -> {
            field.setAccessible(true);
            PrimaryKey primaryKey = field.getAnnotation(PrimaryKey.class);
            if(Objects.nonNull(primaryKey)){
                primaryKeyAtomic.set(field.getName());
                return;
            }
        });
        if(Objects.isNull(primaryKeyAtomic.get())){
            throw new BatisException("实体类未配置PrimaryKey注解...");
        }
        return primaryKeyAtomic.get();
    }


    /**
     *  构建sql返回对象列
     * @param configuration
     * @param entityClass
     * @return
     */
    public static ResultMap getResultMap(Configuration configuration, Class<?> entityClass){
        List<ResultMapping> resultMappings = new ArrayList<ResultMapping>();
        List<Field> fieldList = getClassField(entityClass);
        fieldList.stream().forEach(field -> {
            if(Modifier.isStatic(field.getModifiers()) || Modifier.isFinal(field.getModifiers())){
                return;
            }
            String column = BatisHelper.filedToLowCase(field.getName());
            ResultMapping.Builder builder = new ResultMapping.Builder(configuration, field.getName(), column, field.getType());

            resultMappings.add(builder.build());
        });

        ResultMap.Builder builder = new ResultMap.Builder(configuration, "BaseMapperResultMap", entityClass, resultMappings, true);
        return builder.build();
    }

    /**
     * 构建Conditional条件参数转换数据库字段列
     * @param conditional
     */
    public static void buildConditionalParameter(Conditional<?> conditional){
        if (Objects.nonNull(conditional.builder.sqls) && !CollectionUtils.isEmpty(conditional.builder.sqls.getSqls())){
            List<Sqls.Creator> creators =conditional.builder.sqls.getSqls();
            creators.forEach(creator -> {
                creator.setKey(BatisHelper.filedToLowCase(creator.getKey()));
            });
        }
        if (Objects.nonNull(conditional.builder.sqls) && Objects.nonNull(conditional.builder.sqls.getCreatorSort())){
            Sqls.CreatorSort creatorSort =conditional.builder.sqls.getCreatorSort();
            List<String> keys = new ArrayList<>();
            creatorSort.getKeys().forEach(key -> {
                key = BatisHelper.filedToLowCase(key);
                keys.add(key);
            });
            creatorSort.setKeys(keys);
        }
    }

}
